package com.jvyou.common.utils.spring;

import com.jvyou.common.utils.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

/**
 * Spring 容器工具类
 * <p>
 * 提供在非Spring管理环境中安全访问容器功能的能力，包括：
 * 1. Bean获取与检查
 * 2. 环境配置访问
 * 3. AOP代理访问
 * </p>
 * <p>
 * 使用示例：
 * <pre>{@code
 * // 获取Bean实例
 * UserService service = SpringUtils.getBean(UserService.class);
 *
 * // 检查配置
 * if (SpringUtils.containsBean("dataSource")) {
 *     // 处理逻辑
 * }
 * }</pre>
 *
 * @author Jvyou
 * @since 1.0
 */
@Component
public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {

    private static ConfigurableListableBeanFactory beanFactory;
    private static ApplicationContext applicationContext;

    @Override
    public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException {
        SpringUtils.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }

    /**
     * 通过名称获取Bean实例
     *
     * @param name Bean名称（不能为空）
     * @param <T>  返回类型
     * @return Bean实例
     * @throws BeansException           如果获取失败
     * @throws IllegalArgumentException 如果名称为空
     */
    @SuppressWarnings("unchecked")
    @NonNull
    public static <T> T getBean(@NonNull String name) throws BeansException {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Bean name must not be empty");
        }
        return (T) beanFactory.getBean(name);
    }

    /**
     * 通过类型获取Bean实例
     *
     * @param clz Bean类型（不能为空）
     * @param <T> 返回类型
     * @return Bean实例
     * @throws BeansException 如果获取失败或存在多个同类型Bean
     */
    @NonNull
    public static <T> T getBean(@NonNull Class<T> clz) throws BeansException {
        return beanFactory.getBean(clz);
    }

    /**
     * 检查容器是否包含指定名称的Bean
     *
     * @param name Bean名称（不能为空）
     * @return 如果包含则返回true
     */
    public static boolean containsBean(@NonNull String name) {
        return beanFactory.containsBean(name);
    }

    /**
     * 检查指定名称的Bean是否为单例
     *
     * @param name Bean名称（不能为空）
     * @return 如果是单例则返回true
     * @throws NoSuchBeanDefinitionException 如果Bean不存在
     */
    public static boolean isSingleton(@NonNull String name) throws NoSuchBeanDefinitionException {
        return beanFactory.isSingleton(name);
    }

    /**
     * 获取Bean的类型
     *
     * @param name Bean名称（不能为空）
     * @return Bean的类型
     * @throws NoSuchBeanDefinitionException 如果Bean不存在
     */
    @Nullable
    public static Class<?> getType(@NonNull String name) throws NoSuchBeanDefinitionException {
        return beanFactory.getType(name);
    }

    /**
     * 获取Bean的别名
     *
     * @param name Bean名称（不能为空）
     * @return 别名数组，如果没有别名则返回空数组
     * @throws NoSuchBeanDefinitionException 如果Bean不存在
     */
    @NonNull
    public static String[] getAliases(@NonNull String name) throws NoSuchBeanDefinitionException {
        return beanFactory.getAliases(name);
    }

    /**
     * 获取当前AOP代理对象（需在代理方法内调用）
     * <p>
     * 注意：需在Spring配置中启用expose-proxy
     * <pre>{@code
     * @EnableAspectJAutoProxy(exposeProxy = true)
     * }</pre>
     *
     * @param invoker 当前对象（通常为this）
     * @param <T>     返回类型
     * @return 代理对象
     * @throws IllegalStateException 如果未启用expose-proxy或不在代理上下文中调用
     */
    @SuppressWarnings("unchecked")
    @NonNull
    public static <T> T getAopProxy(@NonNull T invoker) {
        try {
            return (T) AopContext.currentProxy();
        } catch (IllegalStateException e) {
            throw new IllegalStateException("Cannot get AOP proxy. Please ensure @EnableAspectJAutoProxy(exposeProxy=true) is configured", e);
        }
    }

    /**
     * 获取当前激活的环境配置
     *
     * @return 环境配置数组，如果没有则返回空数组
     */
    @NonNull
    public static String[] getActiveProfiles() {
        return applicationContext.getEnvironment().getActiveProfiles();
    }

    /**
     * 获取当前主环境配置
     *
     * @return 主环境配置，如果没有则返回null
     */
    @Nullable
    public static String getActiveProfile() {
        final String[] activeProfiles = getActiveProfiles();
        return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
    }

    /**
     * 获取必须的配置属性
     *
     * @param key 属性键（不能为空）
     * @return 属性值
     * @throws IllegalStateException 如果属性不存在
     */
    @NonNull
    public static String getRequiredProperty(@NonNull String key) {
        try {
            return applicationContext.getEnvironment().getRequiredProperty(key);
        } catch (IllegalStateException e) {
            throw new IllegalStateException("Required property '" + key + "' not found", e);
        }
    }
}